﻿using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using ArgusLib.InteropServices;
using ArgusLib.FFmpeg.avutil;

namespace ArgusLib.FFmpeg.swscale
{
	public class SwsContext : NativeWrapper<Interop.SwsContextNative>
	{
		bool dontDispose = false;
		#region Constructors
		public static SwsContext CreateInstance(int destWidth, int destHeight, AVPixelFormat destPixelFormat, ScalingAlgorithms scalingAlgorithm,
			SwsFilter sourceFilter, SwsFilter destFilter)
		{
			SwsContext swsContext = Interop.Functions.sws_getCachedContext(
				null, 1, 1, AVPixelFormat.AV_PIX_FMT_YUV420P, destWidth, destHeight,destPixelFormat,
				(SWS_Flags)scalingAlgorithm, sourceFilter, destFilter, IntPtr.Zero);

			swsContext.Width = destWidth;
			swsContext.Height = destHeight;
			swsContext.PixelFormat = destPixelFormat;
			swsContext.ScalingAlgorithm = scalingAlgorithm;
			return swsContext;
		}
		#endregion

		#region Properties
		public int Width{get; set;}
		public int Height{get; set;}
		public AVPixelFormat PixelFormat{get;set;}
		public ScalingAlgorithms ScalingAlgorithm{get;set;}
		#endregion

		#region Methods
		protected override void DisposeCore()
		{
			if (this.dontDispose == false)
				Interop.Functions.sws_freeContext(this);
		}

		private void Update(AVVideoFrame sourceFrame, AVVideoFrame destFrame)
		{
			if (destFrame != null)
			{
				this.Width = destFrame.Width;
				this.Height = destFrame.Height;
				this.PixelFormat = destFrame.PixelFormat;
			}

			IntPtr ptr = Interop.Functions.sws_getCachedContext(
				this.Pointer,
				sourceFrame.Width, sourceFrame.Height, sourceFrame.PixelFormat,
				this.Width, this.Height, this.PixelFormat, (SWS_Flags)this.ScalingAlgorithm, null, null, IntPtr.Zero);

			if (ptr == this.Pointer)
				return;

			this.dontDispose = true;
			this.Dispose();
			this.dontDispose = false;

			INativeWrapper wrapper = (INativeWrapper)this;
			wrapper.Initialize(Marshal.PtrToStructure(ptr, wrapper.StructureType), ptr);
		}

		public AVVideoFrame Scale(AVVideoFrame sourceFrame)
		{
			this.Update(sourceFrame, null);
			AVVideoFrame destFrame = AVVideoFrame.CreateInstance(this.PixelFormat, this.Width, this.Height);
			Interop.Functions.sws_scale(this, sourceFrame.ImageData, sourceFrame.Strides, 0, sourceFrame.Height, destFrame.ImageData, destFrame.Strides);
			return destFrame;
		}

		public void Scale(AVVideoFrame sourceFrame, AVVideoFrame destFrame)
		{
			this.Update(sourceFrame, destFrame);
			Interop.Functions.sws_scale(this, sourceFrame.ImageData, sourceFrame.Strides, 0, sourceFrame.Height, destFrame.ImageData, destFrame.Strides);
		}
		#endregion
	}
}
